<template>
	<div class="tree_container">
		<div class="buttons">
			<el-button round type="default" @click="resetChecked">清空</el-button>
			<el-button round type="success" @click="checkAll">全选</el-button>
			<el-button round color="#0099ff" @click="toggleExpand">{{ isExpandAll ? "收起" : "展开" }}</el-button>
		</div>
		<el-tree
			ref="treeRef"
			node-key="id"
			:props="treeProps"
			:data="treeData"
			:show-checkbox="true"
			:default-checked-keys="fixedIds"
			:default-expand-all="false"
			:expand-on-click-node="false"
			:check-on-click-node="true"
			@check-change="onCheckChange"
		>
			<template v-slot:default="{ node, data }">
				<slot :scope="{ node, data }">
					<span>{{ node.label }}</span>
				</slot>
			</template>
		</el-tree>
	</div>
</template>

<script setup lang="ts" name="permissionTree">
import { ref, watch, onMounted } from "vue";
import { debounce } from "lodash";

// 定义父组件传过来的值
interface PermissionTreeProps {
	modelValue: (string | number)[]; // 选中的节点
	treeData: EmptyObjectType[]; // 树形数据
	treeProps?: { label: string; children: string; disabled: string }; // 树形数据的 props 属性
	fixedIds?: (string | number)[]; // 固定选中的节点
}
const props = withDefaults(defineProps<PermissionTreeProps>(), {
	treeProps: () => ({
		label: "label",
		children: "children",
		disabled: "disabled",
	}),
	fixedIds: () => [],
});

// 定义父组件可触发的事件
const emit = defineEmits(["update:modelValue"]);

// 定义变量内容
const treeRef = ref();
const treeIds: (string | number)[] = []; // 全id数组
const fatherIds: (string | number)[] = []; // 父级id数组
const isExpandAll = ref(false); // 是否展开全部

// 重置选中
const resetChecked = () => {
	treeRef.value.setCheckedKeys(props.fixedIds, false);
};
// 全部选中
const checkAll = () => {
	treeRef.value.setCheckedKeys(treeIds, false);
};
// 切换展开状态
const toggleExpand = () => {
	isExpandAll.value = !isExpandAll.value;
	for (let i = 0; i < fatherIds.length; i++) {
		treeRef.value.store.nodesMap[fatherIds[i]].expanded = isExpandAll.value;
	}
};
// 选中状态发生变化时触发
const onCheckChange = debounce(() => {
	emit("update:modelValue", [...treeRef.value.getCheckedKeys(false), ...treeRef.value.getHalfCheckedKeys()]);
}, 500);

// 计算全id数组
const calcTreeIds = (data: any[]) => {
	for (let i = 0; i < data.length; i++) {
		treeIds.push(data[i].id);
		if (data[i][props.treeProps.children] && data[i][props.treeProps.children].length > 0) {
			calcTreeIds(data[i][props.treeProps.children]);
		}
	}
};
// 计算父级id数组
const calcFatherIds = (data: any[]) => {
	for (let i = 0; i < data.length; i++) {
		if (data[i][props.treeProps.children] && data[i][props.treeProps.children].length > 0) {
			fatherIds.push(data[i].id);
			calcFatherIds(data[i][props.treeProps.children]);
		}
	}
};
// 设置选中的节点
const onSetCheckedKeys = (keys: (string | number)[]) => {
	const checkedKeys = keys.filter(item => !fatherIds.includes(item));
	treeRef.value.setCheckedKeys(checkedKeys, false);
};

// 组件挂载时，设置选中的节点
onMounted(() => {
	calcTreeIds(props.treeData);
	calcFatherIds(props.treeData);
	onSetCheckedKeys(props.modelValue.length > 0 ? props.modelValue : props.fixedIds);
});
// 监听 props.modelValue 的变化，设置选中的节点
watch(
	() => props.modelValue,
	() => onSetCheckedKeys(props.modelValue.length > 0 ? props.modelValue : props.fixedIds)
);
</script>

<style scoped lang="scss">
.tree_container {
	width: 100%;
	.buttons {
		display: flex;
		margin-bottom: 10px;
	}
}
</style>
